﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using DigitsExtractor;
using DigitsRecognizer.BussinesLogic;
using NeuralNetwork;

namespace DigitsRecognizer.UI
{
    public class PatternsForm : Form
    {
        private string Login = "piotrek";
        private Label DescriptionLabel, DigitLabel;
        private Button SaveButton, CancelButton, LoadButton, ClearButton;
        private ComboBox ComboBox;
        private FileDialog FileDialog;

        private float[] PictureSize;
        private float[] DrawAreaCoord;
        private DrawField[,] DrawArea;
        private bool ReadyToDraw;
        private bool IsKeyPressed;
        private Writer<double> Writer;
        private string[] Numbers;
        private DigitExtractor DigitExtractor;

        /* rysowanie */
        private Graphics Surface;
        private Pen BlackPen;
        /* pędzel do wypełnienia figury wewnątrz obiektu */
        private SolidBrush WhiteBrush, BlackBrush;
        private Bitmap PixelBitmap;

        public PatternsForm() 
        {
            FillConstans(); 
            this.Height = 300;
            this.Width = 300;
            this.CenterToScreen();
            this.MinimizeBox = false;
            this.MaximizeBox = false;
            this.Text = "Tworzenie zbioru treningowego";

            DescriptionLabel = new Label();
            DescriptionLabel.AutoSize = true;
            DescriptionLabel.Text = "Tworzenie zbioru treningowego";
            DescriptionLabel.Location = new Point(35, 10);
            DescriptionLabel.Font = new Font(new FontFamily(System.Drawing.Text.GenericFontFamilies.SansSerif), 10, FontStyle.Italic);

            DigitLabel = new Label();
            DigitLabel.AutoSize = true;
            DigitLabel.Text = "Cyfra: ";
            DigitLabel.Location = new Point(22, 195);

            ComboBox = new ComboBox();
            ComboBox.Items.AddRange(Numbers);
            ComboBox.Location = new Point(65, 190);
            ComboBox.IntegralHeight = false;
            ComboBox.MaxDropDownItems = 10;
            ComboBox.DropDownStyle = ComboBoxStyle.DropDownList;
            ComboBox.Name = "Cyfry";
            ComboBox.TabIndex = 0;
            ComboBox.Width = 80;

            ClearButton = new Button();
            ClearButton.Text = "Wyczyść";
            ClearButton.Location = new Point(180, 189);

            SaveButton = new Button();
            SaveButton.Text = "Zapisz";
            SaveButton.Location = new Point(22, 230);

            LoadButton = new Button();
            LoadButton.Text = "Wczytaj";
            LoadButton.Location = new Point(102, 230);

            CancelButton = new Button();
            CancelButton.Text = "Powrót";
            CancelButton.Location = new Point(182, 230);

            FileDialog = new OpenFileDialog();
            FileDialog.Title = "Wczytaj plik do trenowania";
            FileDialog.InitialDirectory = Application.StartupPath;
            FileDialog.Filter = "Image File For Testing(*.BMP;)|*.BMP;|All files (*.*)|*.*";

            this.Controls.Add(DescriptionLabel);
            this.Controls.Add(DigitLabel);
            this.Controls.Add(ComboBox);
            this.Controls.Add(SaveButton);
            this.Controls.Add(ClearButton);
            this.Controls.Add(LoadButton);
            this.Controls.Add(CancelButton);

            // Rysowanie miejsca do wpisywania cyfry
            Surface = this.CreateGraphics();
            BlackPen = new Pen(Color.Black, 1.0f);
            WhiteBrush = new SolidBrush(Color.White);
            BlackBrush = new SolidBrush(Color.Black);  

            /* obsługa wciśnięcia przycisku Cancel */
            EventHandler cancelButtonEH = new EventHandler(OnClickCancel);
            CancelButton.Click += cancelButtonEH;

            /* obsługa wciśnięcia przycisku Load */
            EventHandler loadButtonEH = new EventHandler(OnClickLoad);
            LoadButton.Click += loadButtonEH;

            /* obsługa wciśnięcia przycisku Save */
            EventHandler saveButtonEH = new EventHandler(OnClickSave);
            SaveButton.Click += saveButtonEH;

            /* obsługa wciśnięcia przycisku Clear */
            EventHandler clearButtonEH = new EventHandler(OnClickClear);
            ClearButton.Click += clearButtonEH;

            this.KeyPreview = true;
            this.KeyDown += new KeyEventHandler(OnKeyDown);
            this.KeyUp += new KeyEventHandler(OnKeyUp);
            this.Paint += new PaintEventHandler(OnPaint);
            this.MouseDown += new MouseEventHandler(OnMouseDown);
            this.MouseUp += new MouseEventHandler(OnMouseUp);
        }

        public PatternsForm(string login) : this()
        {
            Login = login;
        }

        private void OnClickCancel(object sender, EventArgs args)
        {
            this.Close();
        }

        private void OnClickLoad(object sender, EventArgs args)
        {
            int selectedValue = Convert.ToInt32(ComboBox.Text);
            if (selectedValue == -1)
            {
                MessageBox.Show("Wybierz wartość wczytywanej z pliku cyfry!", "Brak wybranej cyfry z listy", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            else
            {
                FileDialog.ShowDialog();
                // ekstrakcja parametrów do pliku
                if (Writer.SavaParams(DigitExtractor.LoadDigit(FileDialog.FileName), Convert.ToDouble(selectedValue), Login))
                {
                    MessageBox.Show("Wczytaną cyfrę dodano do zbioru treningowego.", "Wczytywanie cyfry z pliku", MessageBoxButtons.OK, MessageBoxIcon.Information);
                }
                else 
                {
                    MessageBox.Show("Błąd! Wczytanej cyfry nie można dodać do zbioru treningowego.", "Wczytywanie cyfry z pliku", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
                
                FileDialog.FileName = ""; 
            }
        }

        private void OnClickSave(object sender, EventArgs args)
        {
            int selectedValue = ComboBox.SelectedIndex;
            if (selectedValue == -1)
            {
                MessageBox.Show("Wybierz wartość wczytywanej z pliku cyfry!", "Brak wybranej cyfry z listy", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            else
            {
                // ekstrakcja parametrów do pliku
                if (Writer.SavaParams(DigitExtractor.ConvertToByte(DrawArea, (int)PictureSize[0], (int)PictureSize[1]), Convert.ToDouble(ComboBox.SelectedItem), Login))
                {
                    MessageBox.Show("Wpisaną cyfrę dodano do zbioru treningowego.", "Wczytywanie wpisanej cyfry", MessageBoxButtons.OK, MessageBoxIcon.Information);
                    OnClickClear(this, new EventArgs());
                }
                else
                {
                    MessageBox.Show("Błąd! Wpisanej cyfry nie można dodać do zbioru treningowego.", "Wczytywanie wpisanej cyfry", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }
        }

        private void OnClickClear(object sender, EventArgs args)
        {
            Clear();
            OnPaint(this, new PaintEventArgs(Surface, this.ClientRectangle));
        }

        private void OnPaint(object sender, PaintEventArgs e)
        {
            DrawBackground();
            DrawDigit();
        }

        private void OnMouseDown(object sender, MouseEventArgs e)
        {
            if (e.X >= DrawArea[0, 0].Coordinates.X && e.X <= DrawArea[0, (int)PictureSize[0] - 1].Coordinates.X &&
                e.Y >= DrawArea[0, 0].Coordinates.Y && e.Y <= DrawArea[(int)PictureSize[1] - 1, 0].Coordinates.Y)
            {
                ReadyToDraw = true;
                SetPixel(new Point(e.X, e.Y));
                this.Paint -= new PaintEventHandler(OnPaint);
                this.MouseMove += new MouseEventHandler(OnMouseMove);
            }
        }

        private void OnMouseUp(object sender, MouseEventArgs e)
        {
            this.MouseMove -= new MouseEventHandler(OnMouseMove);
            OnPaint(this, new PaintEventArgs(Surface, this.ClientRectangle));
            ReadyToDraw = false;
        }

        private void OnMouseMove(object sender, MouseEventArgs e)
        {
            if (e.X >= DrawArea[0, 0].Coordinates.X && e.X <= DrawArea[0, (int)PictureSize[0] - 1].Coordinates.X &&
                e.Y >= DrawArea[0, 0].Coordinates.Y && e.Y <= DrawArea[(int)PictureSize[1] - 1, 0].Coordinates.Y && ReadyToDraw)
            {
                ReadyToDraw = true;
                SetPixel(new Point(e.X, e.Y));
            }
            else 
            {
                ReadyToDraw = false;
            }
        }

        private void OnKeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.ControlKey)
            {
                IsKeyPressed = true;
            }
        }

        private void OnKeyUp(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.ControlKey)
            {
                IsKeyPressed = false;
            }
        }

        private void DrawBackground()
        {
            Surface.FillRectangle(BlackBrush, DrawArea[0, 0].Coordinates.X - 1, DrawArea[0, 0].Coordinates.Y - 1, PictureSize[0] + 2, PictureSize[1] + 2);
            Surface.FillRectangle(WhiteBrush, DrawArea[0, 0].Coordinates.X, DrawArea[0, 0].Coordinates.Y, PictureSize[0], PictureSize[1]); 
        }

        private void FillConstans() 
        {
            Writer = new Writer<double>();
            DigitExtractor = new DigitExtractor();
            PixelBitmap = new Bitmap(1, 1);
            PixelBitmap.SetPixel(0, 0, Color.Black);
            Numbers = new string[] { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" };
            PictureSize = new float[] { 66.0f, 100.0f };
            DrawAreaCoord = new float[] { 110.0f, 55.0f, 110.0f + PictureSize[0], 55.0f + PictureSize[1] };
            DrawArea = new DrawField[(int)PictureSize[1], (int)PictureSize[0]];
            for (int i = 0; i < (int)PictureSize[1]; i++) 
            {
                for (int j = 0; j < (int)PictureSize[0]; j++)
                {
                    DrawArea[i, j] = new DrawField(new Point((int)DrawAreaCoord[0] + j, (int)DrawAreaCoord[1] + i));
                }
            }
        }

        private void SetPixel(Point point) 
        {
            for (int i = 0; i < (int)PictureSize[1]; i++)
            {
                for (int j = 0; j < (int)PictureSize[0]; j++)
                {
                    if (DrawArea[i, j] == point) 
                    {
                        DrawArea[i, j].IsDrawn = IsKeyPressed ? false : true;

                        if (i - 1 > 0) 
                        {
                            DrawArea[i - 1, j].IsDrawn = IsKeyPressed ? false : true;
                        }
                        if (i + 1 < (int)PictureSize[1])
                        {
                            DrawArea[i + 1, j].IsDrawn = IsKeyPressed ? false : true;
                        }
                        if (j - 1 > 0)
                        {
                            DrawArea[i, j - 1].IsDrawn = IsKeyPressed ? false : true;
                        }
                        if (j + 1 < (int)PictureSize[0])
                        {
                            DrawArea[i, j + 1].IsDrawn = IsKeyPressed ? false : true;
                        }
                        break;
                    }
                }
            }
        }

        private void DrawDigit() 
        {
            for (int i = 0; i < (int)PictureSize[1]; i++)
            {
                for (int j = 0; j < (int)PictureSize[0]; j++)
                {
                    if(DrawArea[i, j].IsDrawn)
                    {
                        Surface.DrawImageUnscaled(PixelBitmap,DrawArea[i, j].Coordinates);
                    }
                }
            }
        }

        private void Clear() 
        {
            for (int i = 0; i < (int)PictureSize[1]; i++)
            {
                for (int j = 0; j < (int)PictureSize[0]; j++)
                {
                    if (DrawArea[i, j].IsDrawn)
                    {
                        DrawArea[i, j].IsDrawn = false;
                    }
                }
            }
        }
    }
}
